// 设置全局环境兼容 Node.js

// 模拟整个 thingsmodes.js 模块
const createMockModule1 = () => {
var COMMAND_POST = 0x01; // 属性上报
var COMMAND_EVENT = 0x02; // 事件上报
var COMMAND_PACK = 0x03; // 批量上报
var COMMAND_HISTORY = 0x04; // 历史上报
var COMMAND_POST_REPLY = 0x00; // 上报数据返回结果

var COMMAND_SET = 0x05; // 属性设置设备返回结果
var COMMAND_SET_REPLY = 0x15; // 属性设置设备返回结果
var COMMAND_GET = 0x06; // 属性获取
var COMMAND_GET_REPLY = 0x16; // 属性获取返回

var STR_FRM_START = "`(' [\"{~[";

var DEV_TYPE_TEMP = 0x01;
var DEV_TYPE_VALVLE_CTL = 0x02;
var DEV_TYPE_VALVLE = 0x03;
var DEV_TYPE_ROOM_METER = 0x04;
var DEV_TYPE_BUILD_METER = 0x05;
var DEV_TYPE_ELE_METER = 0x06;
var DEV_TYPE_WATER_METER = 0x07;
var DEV_TYPE_FLOW_VALVE = 0x08;
var DEV_TYPE_LOC = 0x09;
var DEV_TYPE_TFV = 0x0a;
var DEV_TYPE_HEAT_PUMP = 0x0b;
var JZ_CMD_UP_ACQU_DATA = 0x0C;

var JZ_CMD_UP_CFG = 0x51;
var JZ_CMD_UP_REBOOT = 0x52;
var JZ_CMD_UP_RECON = 0x53;
var JZ_CMD_UP_DBGINFO = 0x54;

var JZ_CMD_SET_REPLY = 0x80;

var JZ_CMD_DOWN_INT=0x0481;  // acqInt
var JZ_CMD_DOWN_CFG_CH=0x0482;  // strCmd
var JZ_CMD_DOWN_REBOOT=0x0483;  // strCmd
var JZ_CMD_DOWN_RECON=0x0484;  // strCmd
var JZ_CMD_DOWN_AUTH_PRE=0x0485;  // binCmd
var JZ_CMD_DOWN_AUTH_OK=0x0486;  // authState
var JZ_CMD_DOWN_AUTH_ERR=0x0487;  // authState
var JZ_CMD_DOWN_UPLOAD=0x0488;  // strCmd
var JZ_CMD_DOWN_UPCFG=0x0489;  // strCmd
var JZ_CMD_DOWN_UPRTP=0x048A;  // strCmd
var JZ_CMD_DOWN_SETRTC=0x048B;  // strCmd
var JZ_CMD_DOWN_BUS=0x048C;  // binCmd
var JZ_CMD_DOWN_DEVINFO=0x048D;  // binCmd
var JZ_CMD_DOWN_PASER=0x048E;  // binCmd

var JZ_CMD_DOWN_DATA_REPLY = 0x04A0;  // CMD ACK
var JZ_CMD_DOWN_DATA_START = 0x04A1;  // 
var JZ_CMD_DOWN_DATA_STOP = 0x04A2;  // 
var JZ_CMD_RT_HPMP_START = 0x0215;
var JZ_CMD_RT_HPMP_STOP = 0x0216;
var JZ_CMD_RT_FV_SET_ANGLE = 0x0228;

var THING_PROP_POST_METHOD = 'thing.property.post';
var THING_EVENT_POST_METHOD = 'thing.event.post';
var THING_PACK_POST_METHOD = 'thing.pack.post';
var THING_HISOTORY_METHOD = 'thing.history.post';
var THING_POST_REPLY_METHOD = 'thing.post.reply';
var THING_PROP_SET_METHOD = 'thing.property.set';
var THING_PROP_SET_REPLY_METHOD = 'thing.property.set.reply';
var THING_PROP_GET_METHOD = 'thing.property.get';
var THING_PROP_GET_REPLY_METHOD = 'thing.property.get.reply';
/**
 * 上行解析函数，将设备上报的自定义二进制数据解析为平台物模型数据
 * 可实现两类数据的解析：设备数据上报及设备命令响应数据
 * @params rawData byte[]数组 设备上报的二进制字节数组
 * @return jsonObj json对象 解析后的物模型json数据，格式见文档说明
 */
// 
//
function rawDataToJson(rawData){
    
    var jsonMap = { 'version': '1.0' };
    var dataCs = 0;
    var frmLength = rawData.length - 2;  //cs 0xFF
    var csOk = false;
    var devNum = 0;
    var frmDataLen = 0;
    var devData;
    var devDataLen = 32;
    var devCode;
    var heatTotal;
    var heatUnit;
    var powerCur;
    var powerUnit;
    var flowCur;
    var flowUnit;
    var volTotal;
    var volUnit;
    var tempFor;
    var tempRet;
    var devState;
    var openValue;
    var openControl;
    var dbgStr = "";
    var dateTime;
    var frmData = new Uint8Array(rawData);
    var dataTime;
	var msgId = 0;
	var protocolCode = 0;

    jsonMap.method = THING_PROP_POST_METHOD;
    // check cs
    frmData[frmLength + 1] = 0x00;
    console.log('frmData1112:', frmData, frmLength);
    console.log('断点2',rawData);
    for(var i = 0; i < frmLength; i++ )
    {
        console.log('frmData1113:', rawData[i], frmData[frmLength+1]);
        frmData[frmLength + 1] += rawData[i];
    }
    // check frame
    
    console.log('frmData1111:', frmData);
    console.log('断点1', frmData[frmLength + 1] , frmData[frmLength], frmLength);
    if((frmData[frmLength + 1] === frmData[frmLength]) && ((frmData[0]) === 0xaa) && ((frmData[1]) === 0xe2))
    {
        csOk = true;
    }
    else
    {
        jsonMap.id =  '' + '5001';
        jsonMap.params = { 
			'deviceName':{'value': "ACQU"},};   
        return jsonMap;
    }
    
    // check frame length
    frmDataLen = frmData[2] + frmData[3]*256;
    console.log('frmDataLen1115:', frmDataLen, rawData.length);
    if((frmDataLen + 5) != rawData.length)
    {
        jsonMap.id =  '' + '5002';
        jsonMap.params = { 
			'deviceName':{'value': "ACQU"},};   
        return jsonMap;
    }
    
    // frmData[14] is device data start.
    var dataView = new DataView(frmData.buffer, 0);    
    var revId;
    revId = dataView.getUint32(14, true);
    msgId = revId.toString();
console.log('msgId1111:', msgId);
    // check command type
    if(frmData[9] == 0x04)  // for device upload
    {    
        switch (frmData[8]) 
        {
            case DEV_TYPE_ROOM_METER:
            case DEV_TYPE_BUILD_METER:
                protocolCode = dataView.getUint8(19, true);
                
                dateTime = "20" + frmData[14].toString() + "," + frmData[15].toString() + "," + frmData[16].toString() + " " +  frmData[17].toString() + ":" +  frmData[18].toString() + ":" +  "00";
                dataTime = new Date(dateTime).getTime();
                
                // check device count
                devDataLen = 32;
                devNum = parseInt((frmDataLen - 17)/devDataLen);
/*
                dbgStr = "DAT: cnt:  " + devNum + " " + dateTime + " " + dataTime;
                if(devNum === 0)
                {
                    jsonMap.id =  '' + '5003';
                    jsonMap.params = {'dbg_info': {'value': dbgStr},
						'deviceName':{'value': "ACQU"},};   
                    return jsonMap;
                }
*/
                //else // multi devices
                {
                    var jsonmap1 =  { 'version': '1.0' };
                    var strt;
                    jsonMap.method = THING_PACK_POST_METHOD;
                    jsonMap.id =  '' + '1200';
                    jsonMap.params = []; /*                    
                    jsonMap.params = [{
                            'properties': {
                               'deviceName':{'value': "ACQU"},
                               'dbg_info': {'value': dbgStr}, 
                            }
                        },];    
*/
                                        
                    for(i = 0; i<devNum; i++)
                    {
                        devCode = fixZeroStart(frmData[23 + i*32].toString(16), 2) + fixZeroStart(frmData[22 + i*32].toString(16), 2) + fixZeroStart(frmData[21 + i*32].toString(16), 2) + fixZeroStart(frmData[20 + i*32].toString(16), 2);
                        heatTotal = dataView.getUint32(24 + i*32, true)/100;
                        heatUnit = dataView.getUint8(28 + i*32);
                        powerCur = dataView.getUint32(29 + i*32, true)/100;
                        powerUnit = dataView.getUint8(33 + i*32);
                        flowCur = dataView.getInt32(34 + i*32, true)/10000;
                        //flowUnit = dataView.getUint8(38 + i*32);
                        volTotal = dataView.getUint32(39 + i*32, true)/100;
                        tempFor = dataView.getUint16(44 + i*32, true)/100;
                        tempRet = dataView.getUint16(46 + i*32, true)/100;
                        devState = dataView.getUint16(50 + i*32, true);

                        jsonmap1.params = [{
                            'properties': {
                                'deviceName':{'value': "HMET"},
                                'deviceCode': {'value': devCode},
                                'totalHeat': {'value': heatTotal},  // heat
                                'heatUnit':{'value': heatUnit},
                                'heatPower': {'value': powerCur},  // power
                                'powerUnit':{'value': powerUnit},
                                'flowRate': {'value': flowCur},  // flow
                                'totalFlow': {'value': volTotal}, // volume
                                'supplyTemp': {'value': tempFor},   // temp
                                'returnTemp': {'value': tempRet},
                                'stateCode': {'value': devState},  // state  
                                'aquTime':{'value': dataTime},  // time  
                                'protocolCode':{'value': protocolCode},  //   protocolCode
                            }
                        },]; 
                                        
                        strt = jsonmap1.params[0];
                        jsonMap.params.push(strt);
                    }  
                    
                }
            break;

            case DEV_TYPE_FLOW_VALVE:
                protocolCode = dataView.getUint8(19, true);
                dateTime = "20" + frmData[14].toString() + "," + frmData[15].toString() + "," + frmData[16].toString() + " " +  frmData[17].toString() + ":" +  frmData[18].toString() + ":" +  "00";
                console.log('flv-dateTime: ',dateTime);
                dataTime = new Date(dateTime).getTime();
                
                // check device count
                devDataLen = 17;
                devNum = parseInt((frmDataLen - 17)/devDataLen);
                //else // multi devices
                {
                    var jsonmap1 =  { 'version': '1.0' };
                    var strt;
                    jsonMap.method = THING_PACK_POST_METHOD;
                    jsonMap.id =  '' + '1200';
                    jsonMap.params = [];
                                        
                    for(i = 0; i<devNum; i++)
                    {
                        devCode = fixZeroStart(frmData[27 + i*devDataLen].toString(16), 2) + fixZeroStart(frmData[26 + i*devDataLen].toString(16), 2)
                                + fixZeroStart(frmData[25 + i*devDataLen].toString(16), 2) + fixZeroStart(frmData[24 + i*devDataLen].toString(16), 2)
                                + fixZeroStart(frmData[23 + i*devDataLen].toString(16), 2) + fixZeroStart(frmData[22 + i*devDataLen].toString(16), 2) 
                                + fixZeroStart(frmData[21 + i*devDataLen].toString(16), 2) + fixZeroStart(frmData[20 + i*devDataLen].toString(16), 2);
                                
                        tempRet = dataView.getUint16(30 + i*devDataLen, true)/100;
                        openControl = dataView.getUint16(32 + i*devDataLen, true);
                        openValue = dataView.getUint16(34 + i*devDataLen, true);
                        devState = dataView.getUint8(36 + i*devDataLen, true);

                        
                        jsonmap1.params = [{
                            'properties': {
                                'deviceName':{'value': "FLV"},
                                'deviceCode': {'value': devCode},
                                'returnTemp': {'value': tempRet},
                                'openValue': {'value': openValue},
                                'stateCode': {'value': devState},  // state  
                                'aquTime':{'value': dataTime},  // time  
                                'protocolCode':{'value': protocolCode},  //   protocolCode
                            }
                        },]; 
                                        
                        strt = jsonmap1.params[0];
                        jsonMap.params.push(strt);
                    }  
                    
                }
            break;
            
            case JZ_CMD_UP_ACQU_DATA:
                devCode = fixZeroStart(frmData[7].toString(), 2) + fixZeroStart(frmData[6].toString(), 2) + fixZeroStart(frmData[5].toString(), 2) + fixZeroStart(frmData[4].toString(), 2);
                dateTime = "20" + frmData[14].toString() + "," + frmData[15].toString() + "," + frmData[16].toString() + " " +  frmData[17].toString() + ":" +  frmData[18].toString() + ":" +  frmData[19].toString();
                dataTime = new Date(dateTime).getTime();
                jsonMap.method = THING_PROP_POST_METHOD;
                jsonMap.id =  '' + '1200';
                jsonMap.params = {
					'deviceName':{'value': "ACQU"},
                    'deviceCode': {'value': devCode},
                    'stateCode': {'value': 0},  // state  
                    'aquTime':{'value': dataTime},  // time  
                    'swVersion':{'value': dataView.getUint8(21,true).toString(16) + "." + fixZeroStart(dataView.getUint8(20,true).toString(16),2)},
                    'acqInt':{'value': dataView.getInt16(22,true)},
                }; 
                    
            break;

            case JZ_CMD_SET_REPLY:  // 
                jsonMap.method = THING_PROP_SET_REPLY_METHOD;
                jsonMap.id =  '' + msgId;
                jsonMap.code = 200;
                jsonMap.msg = "success";
            break;   
            
            default:  // unkonwn command 
/*            
                jsonMap.id =  '' + '5004';
                jsonMap.params = { 'dbgInfo': {'value': "Sub cmd err :" + frmData[9] + "  " + frmData[8]}, };
           break;
*/
  console.log('未处理的命令类型:', frmData[8]);
  break;
        }
    }
    else
    {
        jsonMap.id =  '' + '5005';
        jsonMap.params = {
			                    'deviceName':{'value': "ACQU"},
                                   };          
    }        
    
    return jsonMap;
}

/**
 * 下行转换函数，将平台下行的物模型JSON数据编码为设备自定义二进制数据
 * 可实现两类数据的转换：平台命令下发及设备上报响应
 * @params jsonObj json对象 平台构造的物模型json数据，格式见文档说明
 * @return rawData byte[]数组 转换后的二进制数据
 */
 //[{"msg":"buffer length error:pid:T2RaE1KIx7,identifier:unit_head_add","code":2028,"method":"thing.post.reply","id":"1200"}Tue Nov 21 2023 10:07:17 GMT+0800 (CST)"]: 
 //[{"msg":"required value:identifier:properties","code":2409,"method":"thing.post.reply","id":"1200"}Tue Nov 21 2023 07:59:17 GMT+0800 (CST) 2023-10-2  7:59:17 137"]: 
 //[{"msg":"request format error","code":2402,"method":"thing.post.reply"}Tue Nov 21 2023 07:39:34 GMT+0800 (CST) 2023-10-2  7:39:34 0"]:  
//up_reply","{"msg":"success","code":200,"method":"thing.post.reply","id":"10001"}"
//down/3","{"method":"thing.property.get","id":"3","params":["open_time","state","temp_ret","temp_room","temp_set","temp_su","valva_angle","valve_mode"],"version":"1.0"}"
//"$sys/5oSThuW2Ty/tflr002/custome/down/13" :  "5e28265b4e44277baae20a000d000000000001000100a5ff"
function jsonToRawData(jsonObj){
    var payloadArray = [];
    // STARTSIG(8) + header(2) + frm_len(2) + dev_id(4) + cmd(2)  + frame_cnt(2) + frame_num(2) + cs(1) + tail(1)
    var rawData = [0x5E, 0x28, 0x26, 0x5B, 0x4E, 0x44, 0x27, 0x7B, 0xaa, 0xe2];
    var body = [];
    var now = new Date(); 
    var jsstr = JSON.stringify(jsonObj);
    var id = jsonObj.id;
    var method = jsonObj.method;
    var id_val = 0;
    var i = 0;
    var frmData;// = new Uint8Array(rawData);
    var dataView;// = new DataView(frmData.buffer, 0);   
    var cmdDown = 0x0000;
    var payOff = 22;
    var frmLen = 10;  //dev_id/cmd_id(4) + cmd(2)  + frame_cnt(2) + frame_num(2)  
    var frmCnt = 0x01;
    var frmNum = 0x01;
    var csVal = 0x00;
    var params;
    var frmLength;
    
 /*
              //jsstr += now.toString();
        payloadArray = jsstr.getBytes("UTF-8");
        for (i = 0; i < payloadArray.length; i++) 
        {
            rawData[i] = payloadArray[i];
        }
        return rawData;  
*/        
    if(method == THING_PROP_SET_METHOD)
    //if(0)
    {
        id = jsonObj.id;
		params = jsonObj.params;
        var deviceName = params.deviceName;
        var deviceCode = params.deviceCode;
        var acqInt = params.acqInt;
	    var openControl = params.openControl;
	  
		payloadArray = payloadArray.concat(rawData);
		
		if((acqInt !== undefined))
		{
		    cmdDown = JZ_CMD_DOWN_INT;
		    body = body.concat(buffer_uint16(acqInt));
		    frmLen += 2;
		}
 		else if((deviceCode !== undefined) && (openControl !== undefined) && (deviceName !== undefined))
		{
		    if(deviceName == "FLV")
		    {
		        var str="";

                str = deviceCode.toString();
                //str = (deviceCode..reverse().join("")).toString();
                for (i = 0; i < str.length/2; i++) 
                {
                    body[(str.length/2)-i-1] = parseInt(parseInt(str.substring(i*2, i*2+2), 16));
                }
                        
                frmLen += str.length/2;
                
            console.log("body before",body);
		        body = body.concat(buffer_uint16(openControl));
            console.log("body after",body);
		        cmdDown = JZ_CMD_RT_FV_SET_ANGLE; 
		        frmLen += 2;
		    }
		    else
		        cmdDown = 0; 
		}       
		else
		{
		    cmdDown = 0;  // unkonwn cmd
		}
		
        payloadArray = payloadArray.concat(buffer_uint16(frmLen));
        payloadArray = payloadArray.concat(buffer_uint32(id))
        payloadArray = payloadArray.concat(buffer_uint16(cmdDown));
        payloadArray = payloadArray.concat(buffer_uint16(frmCnt));
        payloadArray = payloadArray.concat(buffer_uint16(frmNum));
        //payloadArray = payloadArray.concat(buffer_uint32(parseInt(deviceCode, 16)));
        if(frmLen > 10)
        {
            payloadArray = payloadArray.concat(body);
        }
        
        // cs
        var csVal = 0x00;
        for(i=0; i<frmLen+4; i++ )
        {
            csVal += (payloadArray[i+8])&0xff;
        }
        payloadArray = payloadArray.concat(buffer_uint8(csVal));
        payloadArray = payloadArray.concat(buffer_uint8(0xff));
        
        return payloadArray;
    }
    else// if(method == THING_POST_REPLY_METHOD)
    {
        //jsstr += now.toString();
        payloadArray = jsstr.getBytes("UTF-8");
        for (i = 0; i < payloadArray.length; i++) 
        {
            rawData[8+i] = payloadArray[i];
        }
        return rawData;
    }
}

//将8位无符号整形转换为byte数组
function buffer_uint8(value) {
 var uint8Array = new Uint8Array(1);
 var dataView = new DataView(uint8Array.buffer);
 dataView.setUint8(0, value);
 return [].slice.call(uint8Array);
}

//将16位无符号整形转换为byte数组
function buffer_uint16 (value) {
 var uint8Array = new Uint8Array(2)
 var dv = new DataView(uint8Array.buffer, 0)
 dv.setInt16(0, value)
 return [].slice.call(uint8Array)
}

//将32位无符号整形转换为byte数组
function buffer_uint32 (value) {
 var uint8Array = new Uint8Array(4)
 var dv = new DataView(uint8Array.buffer)
 dv.setInt32(0, value, true)
 return [].slice.call(uint8Array)
}

//将64位无符号整形转换为byte数组
function buffer_uint64 (value) {
 var uint8Array = new Uint8Array(8)
 var dv = new DataView(uint8Array.buffer, 1)
 dv.setBigInt64(0, value, true)
 return [].slice.call(uint8Array)
}

function fixZeroStart(str, n)
{
    return (Array(n).join('0') + str).slice(-n);
}


  return {
    rawDataToJson,
    jsonToRawData,
    COMMAND_POST,
    COMMAND_PACK,
    COMMAND_HISTORY,
    COMMAND_SET_REPLY,
    COMMAND_GET_REPLY,
    THING_PROP_POST_METHOD,
    THING_PACK_POST_METHOD,
    THING_HISOTORY_METHOD,
    THING_PROP_SET_REPLY_METHOD,
    THING_POST_REPLY_METHOD,
    THING_PROP_SET_METHOD,
    THING_PROP_GET_METHOD
  };
};

// 创建模拟模块实例
const mockModule1 = createMockModule1();

// 测试用例
describe('物联网协议编解码测试', () => {
  // 1. 测试属性上报解析
  // test('属性上报解析 - 单点数据', () => {
  //   const postData = [mockModule.COMMAND_POST, 0x01, 0x00, 0x07]; // 0x01010007
  //   const result = mockModule.rawDataToJson(postData);
    
  //   expect(result).toEqual({
  //     method: mockModule.THING_PROP_POST_METHOD,
  //     version: '1.0',
  //     id: '1',
  //     params: {
  //       power: {
  //         value: 7
  //       }
  //     }
  //   });
  // });

  // // 2. 测试批量上报解析
  // test('批量上报解析', () => {
  //   const mockDate = new Date('2023-01-01').getTime();
  //   jest.spyOn(Date, 'now').mockImplementation(() => mockDate);
    
  //   const packData = [mockModule.COMMAND_PACK, 0x01, 0x00, 0x0A]; // 0x0301000A
  //   const result = mockModule.rawDataToJson(packData);
    
  //   expect(result).toEqual({
  //     method: mockModule.THING_PACK_POST_METHOD,
  //     version: '1.0',
  //     id: '1',
  //     params: [{
  //       properties: {
  //         power: [{
  //           value: 10,
  //           time: mockDate
  //         }]
  //       }
  //     }]
  //   });
  // });

    test('属性设置回复', () => {
    const mockDate = new Date('2023-01-01').getTime();
    jest.spyOn(Date, 'now').mockImplementation(() => mockDate);
    
    //const packData = [0x80,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00]; // 0x0301000A
const testData = [
  0xaa, 0xe2, // 帧起始标志
  0x0f, 0x00, // 帧长度，假设帧长度为 13 字节
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x80, 0x04, // 其他数据
  0x00, 0x00, 0x00, 0x00, // msgId 为 1
  0x02,       // 设备上传标志
  0x00,       // JZ_CMD_SET_REPLY
  0x00, 0x00,
  0x21,       // 校验和，需要根据实际数据计算
  0xff        // 帧结束标志
];
    const result = mockModule1.rawDataToJson(testData);
    
    console.log('属性设置回复2',result);
    // expect(result).toEqual({
    //   method: mockModule.THING_PACK_POST_METHOD,
    //   version: '1.0',
    //   id: '1',
    //   params: [{
    //     properties: {
    //       power: [{
    //         value: 10,
    //         time: mockDate
    //       }]
    //     }
    //   }]
    // });
  });
test('属性上报数据', () => {
    const mockDate = new Date('2023-01-01').getTime();
    jest.spyOn(Date, 'now').mockImplementation(() => mockDate);
    
    //const packData = [0x80,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00]; // 0x0301000A
// const testData = [
//   0xAA,0xE2,0x31,0x00,0x16,0x16,0x16,0x2A,0x05,0x04,0x01,0x00,0x01,0x00,0x19,0x07,0x08,0x0A,0x0F,0x01,0x17,0x86,0x08,0x23,0x47,0xF4,0x10,0x00,0x05,0x55,0xA0,0xFC,0x01,0x17,0x1C,0x2B,0xA6,0x02,0x00,0x8E,0x15,0x53,0x01,0x00,0xB3,0x15,0x0A,0x1A,0x00,0x00,0x00,0x00,0x69,0xFF
// ];

//const testData = [0xaa,0xe2,0x31,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x00,0x00,0x19,0x07,0x0b,0x10,0x26,0x02,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x00,0x07,0x08,0x00,0x00,0x03,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0xff];
//const testData = [0xaa,0xe2,0x2e,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x00,0x00,0x19,0x07,0x0b,0x10,0x26,0x02,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x00,0x07,0x08,0x00,0x00,0x3c,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xff];
const testData = [0xaa,0xe2,0x2e,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x00,0x00,0x19,0x07,0x0b,0x10,0x26,0x02,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x00,0x07,0x08,0x00,0x00,0x3c,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xff];
const packData = [
  0xaa, 0xe2, // 帧起始标志
  0x31, 0x00, // 帧长度，假设帧长度为 29 字节
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x08,       // DEV_TYPE_FLOW_VALVE
  0x04,       // 设备上传标志
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x19, //年
  0x07, // 月
  0x0b, //日
  0x10, // 时
  0x26, //分
  0x02, // protocolCode
  0x01, 0x02, // deviceCode
  0x03, 0x04, // deviceCode
  0x05, 0x06, // deviceCode
  0x07, 0x08, // deviceCode
  0x00, 0x00, // 其他数据
  0x07, 0x08, // returnTemp
  0x00, 0x00, // 其他数据
  0x03, 0x00, // openValue
  0x09, //stateCode
  0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00
  , 0x00, 0x00, 0x6B, // msgId 为 1
  // 其他数据
  // 校验和
  0xff        // 帧结束标志
];

const packData1 = [
  0xaa, 0xe2, // 帧起始标志
  0x31, 0x00, // 帧长度，假设帧长度为 29 字节
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x05,       // DEV_TYPE_BUILD_METER
  0x04,       // 设备上传标志
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x19, //年
  0x07, // 月
  0x0b, //日
  0x10, // 时
  0x26, //分
  0x02, // protocolCode
  0x01, 0x02, // deviceCode
  0x03, 0x04, // deviceCode
  0x05, 0x06, //heatTotal
  0x07, 0x08, //heatTotal
  0x01,  // heatUnit
  0x00, // 其他数据
  0x07, 0x08, // returnTemp
  0x00, 0x00, // 其他数据
  0x03, 0x04, // openValue
  0x09, //stateCode
  0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00, // 其他数据
  0x00, 0x00
  , 0x00, 0x00, 0x6C, // msgId 为 1
  // 其他数据
  // 校验和
  0xff        // 帧结束标志
];

    const result = mockModule1.rawDataToJson(testData);
    
    console.log('属性上报数据',JSON.stringify(result));

    // expect(result).toEqual({
    //   method: mockModule.THING_PACK_POST_METHOD,
    //   version: '1.0',
    //   id: '1',
    //   params: [{
    //     properties: {
    //       power: [{
    //         value: 10,
    //         time: mockDate
    //       }]
    //     }
    //   }]
    // });
  });
  // // 3. 测试属性设置响应编码
  // test('属性设置响应编码', () => {
  //   const json = {
  //     method: mockModule.THING_PROP_SET_REPLY_METHOD,
  //     id: "2",
  //     code: 200,
  //     data: { power: 8 }
  //   };
    
  //   const result = mockModule.jsonToRawData(json);
  //   console.log(result);
  //   // 0x1502010008 -> [21, 2, 1, 0, 8]
  //   //expect(result).toEqual([mockModule.COMMAND_SET_REPLY, 2, 1, 0, 8]);
  // });

  // 4. 测试属性设置指令编码
  //{"method":"thing.property.set", "version": "1.0", "id": 2, "params":[ {"code": "121", "power": 15 },{"code": "122", "power": 16 }]}
  //{"deviceProp":[ {"code": "121", "power": 15 },{"code": "122", "power": 16 }]}
  test('属性设置指令编码', () => {
    const json = {
      method: mockModule1.THING_PROP_SET_METHOD,
      id: "4",
      params:{"deviceCode":"0807060504030201","deviceName":"FLV","openControl":67}
    };
    
    const result = mockModule1.jsonToRawData(json);
    console.log('属性设置指令编码1161',result);
    const hexString = result.map(byte => byte.toString(16).padStart(2, '0')).join('');
    console.log('属性设置指令编码16进制:', hexString);
    // 0x0503000F -> [5, 3, 0, 15]
    //expect(result).toEqual([mockModule.COMMAND_SET, 3, 0, 15]);
  });

  // // 5. 测试属性获取响应解析
  // test('属性获取响应解析', () => {
  //   const getReply = [mockModule.COMMAND_GET_REPLY, 0x04, 0x01, 0x00, 0x0C]; // 0x160401000C
  //   const result = mockModule.rawDataToJson(getReply);
  //   console.log(result);
  //   // expect(result).toEqual({
  //   //   method: mockModule.THING_PROP_GET_REPLY_METHOD,
  //   //   version: '1.0',
  //   //   id: '4',
  //   //   code: 200,
  //   //   msg: 'success',
  //   //   data: { power: 12 }
  //   // });
  // });
});